package com.fr.base.core.antlr;

import com.fr.base.core.antlr.collections.impl.BitSet;
import com.fr.base.core.antlr.collections.impl.Vector;
import java.io.PrintStream;

public class LLkAnalyzer
  implements LLkGrammarAnalyzer
{
  public boolean DEBUG_ANALYZER = false;
  private AlternativeBlock currentBlock;
  protected Tool tool = null;
  protected Grammar grammar = null;
  protected boolean lexicalAnalysis = false;
  CharFormatter charFormatter = new JavaCharFormatter();

  public LLkAnalyzer(Tool paramTool)
  {
    this.tool = paramTool;
  }

  protected boolean altUsesWildcardDefault(Alternative paramAlternative)
  {
    AlternativeElement localAlternativeElement = paramAlternative.head;
    if ((localAlternativeElement instanceof TreeElement) && (((TreeElement)localAlternativeElement).root instanceof WildcardElement))
      return true;
    return ((localAlternativeElement instanceof WildcardElement) && (localAlternativeElement.next instanceof BlockEndElement));
  }

  public boolean deterministic(AlternativeBlock paramAlternativeBlock)
  {
    int i = 1;
    if (this.DEBUG_ANALYZER)
      System.out.println("deterministic(" + paramAlternativeBlock + ")");
    int j = 1;
    int k = paramAlternativeBlock.alternatives.size();
    AlternativeBlock localAlternativeBlock = this.currentBlock;
    Object localObject1 = null;
    this.currentBlock = paramAlternativeBlock;
    if ((!(paramAlternativeBlock.greedy)) && (!(paramAlternativeBlock instanceof OneOrMoreBlock)) && (!(paramAlternativeBlock instanceof ZeroOrMoreBlock)))
      this.tool.warning("Being nongreedy only makes sense for (...)+ and (...)*", this.grammar.getFilename(), paramAlternativeBlock.getLine(), paramAlternativeBlock.getColumn());
    if (k == 1)
    {
      AlternativeElement localAlternativeElement = paramAlternativeBlock.getAlternativeAt(0).head;
      this.currentBlock.alti = 0;
      paramAlternativeBlock.getAlternativeAt(0).cache[1] = localAlternativeElement.look(1);
      paramAlternativeBlock.getAlternativeAt(0).lookaheadDepth = 1;
      this.currentBlock = localAlternativeBlock;
      return true;
    }
    for (int l = 0; l < k - 1; ++l)
    {
      this.currentBlock.alti = l;
      this.currentBlock.analysisAlt = l;
      this.currentBlock.altj = (l + 1);
      for (int i1 = l + 1; i1 < k; ++i1)
      {
        int i2;
        this.currentBlock.altj = i1;
        if (this.DEBUG_ANALYZER)
          System.out.println("comparing " + l + " against alt " + i1);
        this.currentBlock.analysisAlt = i1;
        i = 1;
        Lookahead[] arrayOfLookahead = new Lookahead[this.grammar.maxk + 1];
        do
        {
          i2 = 0;
          if (this.DEBUG_ANALYZER)
            System.out.println("checking depth " + i + "<=" + this.grammar.maxk);
          localObject2 = getAltLookahead(paramAlternativeBlock, l, i);
          localObject3 = getAltLookahead(paramAlternativeBlock, i1, i);
          if (this.DEBUG_ANALYZER)
            System.out.println("p is " + ((Lookahead)localObject2).toString(",", this.charFormatter, this.grammar));
          if (this.DEBUG_ANALYZER)
            System.out.println("q is " + ((Lookahead)localObject3).toString(",", this.charFormatter, this.grammar));
          arrayOfLookahead[i] = ((Lookahead)localObject2).intersection((Lookahead)localObject3);
          if (this.DEBUG_ANALYZER)
            System.out.println("intersection at depth " + i + " is " + arrayOfLookahead[i].toString());
          if (!(arrayOfLookahead[i].nil()))
          {
            i2 = 1;
            ++i;
          }
        }
        while ((i2 != 0) && (i <= this.grammar.maxk));
        Object localObject2 = paramAlternativeBlock.getAlternativeAt(l);
        Object localObject3 = paramAlternativeBlock.getAlternativeAt(i1);
        if (i2 != 0)
        {
          j = 0;
          ((Alternative)localObject2).lookaheadDepth = 2147483647;
          ((Alternative)localObject3).lookaheadDepth = 2147483647;
          if (((Alternative)localObject2).synPred != null)
          {
            if (this.DEBUG_ANALYZER)
              System.out.println("alt " + l + " has a syn pred");
          }
          else if (((Alternative)localObject2).semPred != null)
          {
            if (this.DEBUG_ANALYZER)
              System.out.println("alt " + l + " has a sem pred");
          }
          else if (altUsesWildcardDefault((Alternative)localObject3))
          {
            localObject1 = localObject3;
          }
          else if (!(paramAlternativeBlock.warnWhenFollowAmbig))
          {
            if (!(((Alternative)localObject2).head instanceof BlockEndElement))
              if (((Alternative)localObject3).head instanceof BlockEndElement);
          }
          else
          {
            if (!(paramAlternativeBlock.generateAmbigWarnings))
              break label868:
            if ((paramAlternativeBlock.greedySet) && (paramAlternativeBlock.greedy))
              if ((!(((Alternative)localObject2).head instanceof BlockEndElement)) || (((Alternative)localObject3).head instanceof BlockEndElement))
                if ((((Alternative)localObject3).head instanceof BlockEndElement) && (!(((Alternative)localObject2).head instanceof BlockEndElement)));
            else
              this.tool.errorHandler.warnAltAmbiguity(this.grammar, paramAlternativeBlock, this.lexicalAnalysis, this.grammar.maxk, arrayOfLookahead, l, i1);
          }
        }
        else
        {
          ((Alternative)localObject2).lookaheadDepth = Math.max(((Alternative)localObject2).lookaheadDepth, i);
          ((Alternative)localObject3).lookaheadDepth = Math.max(((Alternative)localObject3).lookaheadDepth, i);
        }
      }
    }
    label868: this.currentBlock = localAlternativeBlock;
    return j;
  }

  public boolean deterministic(OneOrMoreBlock paramOneOrMoreBlock)
  {
    if (this.DEBUG_ANALYZER)
      System.out.println("deterministic(...)+(" + paramOneOrMoreBlock + ")");
    AlternativeBlock localAlternativeBlock = this.currentBlock;
    this.currentBlock = paramOneOrMoreBlock;
    boolean bool1 = deterministic(paramOneOrMoreBlock);
    boolean bool2 = deterministicImpliedPath(paramOneOrMoreBlock);
    this.currentBlock = localAlternativeBlock;
    return ((bool2) && (bool1));
  }

  public boolean deterministic(ZeroOrMoreBlock paramZeroOrMoreBlock)
  {
    if (this.DEBUG_ANALYZER)
      System.out.println("deterministic(...)*(" + paramZeroOrMoreBlock + ")");
    AlternativeBlock localAlternativeBlock = this.currentBlock;
    this.currentBlock = paramZeroOrMoreBlock;
    boolean bool1 = deterministic(paramZeroOrMoreBlock);
    boolean bool2 = deterministicImpliedPath(paramZeroOrMoreBlock);
    this.currentBlock = localAlternativeBlock;
    return ((bool2) && (bool1));
  }

  public boolean deterministicImpliedPath(BlockWithImpliedExitPath paramBlockWithImpliedExitPath)
  {
    int j = 1;
    Vector localVector = paramBlockWithImpliedExitPath.getAlternatives();
    int k = localVector.size();
    this.currentBlock.altj = -1;
    if (this.DEBUG_ANALYZER)
      System.out.println("deterministicImpliedPath");
    for (int l = 0; l < k; ++l)
    {
      int i1;
      Object localObject;
      Alternative localAlternative = paramBlockWithImpliedExitPath.getAlternativeAt(l);
      if (localAlternative.head instanceof BlockEndElement)
        this.tool.warning("empty alternative makes no sense in (...)* or (...)+", this.grammar.getFilename(), paramBlockWithImpliedExitPath.getLine(), paramBlockWithImpliedExitPath.getColumn());
      int i = 1;
      Lookahead[] arrayOfLookahead = new Lookahead[this.grammar.maxk + 1];
      do
      {
        i1 = 0;
        if (this.DEBUG_ANALYZER)
          System.out.println("checking depth " + i + "<=" + this.grammar.maxk);
        Lookahead localLookahead = paramBlockWithImpliedExitPath.next.look(i);
        paramBlockWithImpliedExitPath.exitCache[i] = localLookahead;
        this.currentBlock.alti = l;
        localObject = getAltLookahead(paramBlockWithImpliedExitPath, l, i);
        if (this.DEBUG_ANALYZER)
          System.out.println("follow is " + localLookahead.toString(",", this.charFormatter, this.grammar));
        if (this.DEBUG_ANALYZER)
          System.out.println("p is " + ((Lookahead)localObject).toString(",", this.charFormatter, this.grammar));
        arrayOfLookahead[i] = localLookahead.intersection((Lookahead)localObject);
        if (this.DEBUG_ANALYZER)
          System.out.println("intersection at depth " + i + " is " + arrayOfLookahead[i]);
        if (!(arrayOfLookahead[i].nil()))
        {
          i1 = 1;
          ++i;
        }
      }
      while ((i1 != 0) && (i <= this.grammar.maxk));
      if (i1 != 0)
      {
        j = 0;
        localAlternative.lookaheadDepth = 2147483647;
        paramBlockWithImpliedExitPath.exitLookaheadDepth = 2147483647;
        localObject = paramBlockWithImpliedExitPath.getAlternativeAt(this.currentBlock.alti);
        if (!(paramBlockWithImpliedExitPath.warnWhenFollowAmbig))
          break label625:
        if (!(paramBlockWithImpliedExitPath.generateAmbigWarnings))
          break label625:
        if ((paramBlockWithImpliedExitPath.greedy == true) && (paramBlockWithImpliedExitPath.greedySet) && (!(((Alternative)localObject).head instanceof BlockEndElement)))
        {
          if (this.DEBUG_ANALYZER)
            System.out.println("greedy loop");
        }
        else if ((!(paramBlockWithImpliedExitPath.greedy)) && (!(((Alternative)localObject).head instanceof BlockEndElement)))
        {
          if (this.DEBUG_ANALYZER)
            System.out.println("nongreedy loop");
          if (!(lookaheadEquivForApproxAndFullAnalysis(paramBlockWithImpliedExitPath.exitCache, this.grammar.maxk)))
            this.tool.warning(new String[] { "nongreedy block may exit incorrectly due", "\tto limitations of linear approximate lookahead (first k-1 sets", "\tin lookahead not singleton)." }, this.grammar.getFilename(), paramBlockWithImpliedExitPath.getLine(), paramBlockWithImpliedExitPath.getColumn());
        }
        else
        {
          this.tool.errorHandler.warnAltExitAmbiguity(this.grammar, paramBlockWithImpliedExitPath, this.lexicalAnalysis, this.grammar.maxk, arrayOfLookahead, l);
        }
      }
      else
      {
        localAlternative.lookaheadDepth = Math.max(localAlternative.lookaheadDepth, i);
        paramBlockWithImpliedExitPath.exitLookaheadDepth = Math.max(paramBlockWithImpliedExitPath.exitLookaheadDepth, i);
      }
    }
    label625: return j;
  }

  public Lookahead FOLLOW(int paramInt, RuleEndElement paramRuleEndElement)
  {
    String str;
    RuleBlock localRuleBlock = (RuleBlock)paramRuleEndElement.block;
    if (this.lexicalAnalysis)
      str = CodeGenerator.encodeLexerRuleName(localRuleBlock.getRuleName());
    else
      str = localRuleBlock.getRuleName();
    if (this.DEBUG_ANALYZER)
      System.out.println("FOLLOW(" + paramInt + "," + str + ")");
    if (paramRuleEndElement.lock[paramInt] != 0)
    {
      if (this.DEBUG_ANALYZER)
        System.out.println("FOLLOW cycle to " + str);
      return new Lookahead(str);
    }
    if (paramRuleEndElement.cache[paramInt] != null)
    {
      if (this.DEBUG_ANALYZER)
        System.out.println("cache entry FOLLOW(" + paramInt + ") for " + str + ": " + paramRuleEndElement.cache[paramInt].toString(",", this.charFormatter, this.grammar));
      if (paramRuleEndElement.cache[paramInt].cycle == null)
        return ((Lookahead)paramRuleEndElement.cache[paramInt].clone());
      localObject1 = (RuleSymbol)this.grammar.getSymbol(paramRuleEndElement.cache[paramInt].cycle);
      localObject2 = ((RuleSymbol)localObject1).getBlock().endNode;
      if (localObject2.cache[paramInt] == null)
        return ((Lookahead)paramRuleEndElement.cache[paramInt].clone());
      if (this.DEBUG_ANALYZER)
        System.out.println("combining FOLLOW(" + paramInt + ") for " + str + ": from " + paramRuleEndElement.cache[paramInt].toString(",", this.charFormatter, this.grammar) + " with FOLLOW for " + ((RuleBlock)((RuleEndElement)localObject2).block).getRuleName() + ": " + localObject2.cache[paramInt].toString(",", this.charFormatter, this.grammar));
      if (localObject2.cache[paramInt].cycle == null)
      {
        paramRuleEndElement.cache[paramInt].combineWith(localObject2.cache[paramInt]);
        paramRuleEndElement.cache[paramInt].cycle = null;
      }
      else
      {
        Lookahead localLookahead1 = FOLLOW(paramInt, (RuleEndElement)localObject2);
        paramRuleEndElement.cache[paramInt].combineWith(localLookahead1);
        paramRuleEndElement.cache[paramInt].cycle = localLookahead1.cycle;
      }
      if (this.DEBUG_ANALYZER)
        System.out.println("saving FOLLOW(" + paramInt + ") for " + str + ": from " + paramRuleEndElement.cache[paramInt].toString(",", this.charFormatter, this.grammar));
      return ((Lookahead)paramRuleEndElement.cache[paramInt].clone());
    }
    paramRuleEndElement.lock[paramInt] = true;
    Object localObject1 = new Lookahead();
    Object localObject2 = (RuleSymbol)this.grammar.getSymbol(str);
    for (int i = 0; i < ((RuleSymbol)localObject2).numReferences(); ++i)
    {
      RuleRefElement localRuleRefElement = ((RuleSymbol)localObject2).getReference(i);
      if (this.DEBUG_ANALYZER)
        System.out.println("next[" + str + "] is " + localRuleRefElement.next.toString());
      Lookahead localLookahead2 = localRuleRefElement.next.look(paramInt);
      if (this.DEBUG_ANALYZER)
        System.out.println("FIRST of next[" + str + "] ptr is " + localLookahead2.toString());
      if ((localLookahead2.cycle != null) && (localLookahead2.cycle.equals(str)))
        localLookahead2.cycle = null;
      ((Lookahead)localObject1).combineWith(localLookahead2);
      if (this.DEBUG_ANALYZER)
        System.out.println("combined FOLLOW[" + str + "] is " + ((Lookahead)localObject1).toString());
    }
    paramRuleEndElement.lock[paramInt] = false;
    if ((((Lookahead)localObject1).fset.nil()) && (((Lookahead)localObject1).cycle == null))
      if (this.grammar instanceof TreeWalkerGrammar)
        ((Lookahead)localObject1).fset.add(3);
      else if (this.grammar instanceof LexerGrammar)
        ((Lookahead)localObject1).setEpsilon();
      else
        ((Lookahead)localObject1).fset.add(1);
    if (this.DEBUG_ANALYZER)
      System.out.println("saving FOLLOW(" + paramInt + ") for " + str + ": " + ((Lookahead)localObject1).toString(",", this.charFormatter, this.grammar));
    paramRuleEndElement.cache[paramInt] = ((Lookahead)((Lookahead)localObject1).clone());
    return ((Lookahead)(Lookahead)localObject1);
  }

  private Lookahead getAltLookahead(AlternativeBlock paramAlternativeBlock, int paramInt1, int paramInt2)
  {
    Lookahead localLookahead;
    Alternative localAlternative = paramAlternativeBlock.getAlternativeAt(paramInt1);
    AlternativeElement localAlternativeElement = localAlternative.head;
    if (localAlternative.cache[paramInt2] == null)
    {
      localLookahead = localAlternativeElement.look(paramInt2);
      localAlternative.cache[paramInt2] = localLookahead;
    }
    else
    {
      localLookahead = localAlternative.cache[paramInt2];
    }
    return localLookahead;
  }

  public Lookahead look(int paramInt, ActionElement paramActionElement)
  {
    if (this.DEBUG_ANALYZER)
      System.out.println("lookAction(" + paramInt + "," + paramActionElement + ")");
    return paramActionElement.next.look(paramInt);
  }

  public Lookahead look(int paramInt, AlternativeBlock paramAlternativeBlock)
  {
    Object localObject;
    if (this.DEBUG_ANALYZER)
      System.out.println("lookAltBlk(" + paramInt + "," + paramAlternativeBlock + ")");
    AlternativeBlock localAlternativeBlock = this.currentBlock;
    this.currentBlock = paramAlternativeBlock;
    Lookahead localLookahead1 = new Lookahead();
    for (int i = 0; i < paramAlternativeBlock.alternatives.size(); ++i)
    {
      if (this.DEBUG_ANALYZER)
        System.out.println("alt " + i + " of " + paramAlternativeBlock);
      this.currentBlock.analysisAlt = i;
      localObject = paramAlternativeBlock.getAlternativeAt(i);
      AlternativeElement localAlternativeElement = ((Alternative)localObject).head;
      if ((this.DEBUG_ANALYZER) && (((Alternative)localObject).head == ((Alternative)localObject).tail))
        System.out.println("alt " + i + " is empty");
      Lookahead localLookahead2 = localAlternativeElement.look(paramInt);
      localLookahead1.combineWith(localLookahead2);
    }
    if ((paramInt == 1) && (paramAlternativeBlock.not) && (subruleCanBeInverted(paramAlternativeBlock, this.lexicalAnalysis)))
      if (this.lexicalAnalysis)
      {
        BitSet localBitSet = (BitSet)((LexerGrammar)this.grammar).charVocabulary.clone();
        localObject = localLookahead1.fset.toArray();
        for (int j = 0; j < localObject.length; ++j)
          localBitSet.remove(localObject[j]);
        localLookahead1.fset = localBitSet;
      }
      else
      {
        localLookahead1.fset.notInPlace(4, this.grammar.tokenManager.maxTokenType());
      }
    this.currentBlock = localAlternativeBlock;
    return ((Lookahead)localLookahead1);
  }

  public Lookahead look(int paramInt, BlockEndElement paramBlockEndElement)
  {
    Lookahead localLookahead1;
    if (this.DEBUG_ANALYZER)
      System.out.println("lookBlockEnd(" + paramInt + ", " + paramBlockEndElement.block + "); lock is " + paramBlockEndElement.lock[paramInt]);
    if (paramBlockEndElement.lock[paramInt] != 0)
      return new Lookahead();
    if ((paramBlockEndElement.block instanceof ZeroOrMoreBlock) || (paramBlockEndElement.block instanceof OneOrMoreBlock))
    {
      paramBlockEndElement.lock[paramInt] = true;
      localLookahead1 = look(paramInt, paramBlockEndElement.block);
      paramBlockEndElement.lock[paramInt] = false;
    }
    else
    {
      localLookahead1 = new Lookahead();
    }
    if (paramBlockEndElement.block instanceof TreeElement)
    {
      localLookahead1.combineWith(Lookahead.of(3));
    }
    else if (paramBlockEndElement.block instanceof SynPredBlock)
    {
      localLookahead1.setEpsilon();
    }
    else
    {
      Lookahead localLookahead2 = paramBlockEndElement.block.next.look(paramInt);
      localLookahead1.combineWith(localLookahead2);
    }
    return localLookahead1;
  }

  public Lookahead look(int paramInt, CharLiteralElement paramCharLiteralElement)
  {
    if (this.DEBUG_ANALYZER)
      System.out.println("lookCharLiteral(" + paramInt + "," + paramCharLiteralElement + ")");
    if (paramInt > 1)
      return paramCharLiteralElement.next.look(paramInt - 1);
    if (this.lexicalAnalysis)
    {
      if (paramCharLiteralElement.not)
      {
        BitSet localBitSet = (BitSet)((LexerGrammar)this.grammar).charVocabulary.clone();
        if (this.DEBUG_ANALYZER)
          System.out.println("charVocab is " + localBitSet.toString());
        removeCompetingPredictionSets(localBitSet, paramCharLiteralElement);
        if (this.DEBUG_ANALYZER)
          System.out.println("charVocab after removal of prior alt lookahead " + localBitSet.toString());
        localBitSet.clear(paramCharLiteralElement.getType());
        return new Lookahead(localBitSet);
      }
      return Lookahead.of(paramCharLiteralElement.getType());
    }
    this.tool.panic("Character literal reference found in parser");
    return Lookahead.of(paramCharLiteralElement.getType());
  }

  public Lookahead look(int paramInt, CharRangeElement paramCharRangeElement)
  {
    if (this.DEBUG_ANALYZER)
      System.out.println("lookCharRange(" + paramInt + "," + paramCharRangeElement + ")");
    if (paramInt > 1)
      return paramCharRangeElement.next.look(paramInt - 1);
    BitSet localBitSet = BitSet.of(paramCharRangeElement.begin);
    for (int i = paramCharRangeElement.begin + '\1'; i <= paramCharRangeElement.end; ++i)
      localBitSet.add(i);
    return new Lookahead(localBitSet);
  }

  public Lookahead look(int paramInt, GrammarAtom paramGrammarAtom)
  {
    if (this.DEBUG_ANALYZER)
      System.out.println("look(" + paramInt + "," + paramGrammarAtom + "[" + paramGrammarAtom.getType() + "])");
    if (this.lexicalAnalysis)
      this.tool.panic("token reference found in lexer");
    if (paramInt > 1)
      return paramGrammarAtom.next.look(paramInt - 1);
    Lookahead localLookahead = Lookahead.of(paramGrammarAtom.getType());
    if (paramGrammarAtom.not)
    {
      int i = this.grammar.tokenManager.maxTokenType();
      localLookahead.fset.notInPlace(4, i);
      removeCompetingPredictionSets(localLookahead.fset, paramGrammarAtom);
    }
    return localLookahead;
  }

  public Lookahead look(int paramInt, OneOrMoreBlock paramOneOrMoreBlock)
  {
    if (this.DEBUG_ANALYZER)
      System.out.println("look+" + paramInt + "," + paramOneOrMoreBlock + ")");
    Lookahead localLookahead = look(paramInt, paramOneOrMoreBlock);
    return localLookahead;
  }

  public Lookahead look(int paramInt, RuleBlock paramRuleBlock)
  {
    if (this.DEBUG_ANALYZER)
      System.out.println("lookRuleBlk(" + paramInt + "," + paramRuleBlock + ")");
    Lookahead localLookahead = look(paramInt, paramRuleBlock);
    return localLookahead;
  }

  public Lookahead look(int paramInt, RuleEndElement paramRuleEndElement)
  {
    if (this.DEBUG_ANALYZER)
      System.out.println("lookRuleBlockEnd(" + paramInt + "); noFOLLOW=" + paramRuleEndElement.noFOLLOW + "; lock is " + paramRuleEndElement.lock[paramInt]);
    if (paramRuleEndElement.noFOLLOW)
    {
      localLookahead = new Lookahead();
      localLookahead.setEpsilon();
      localLookahead.epsilonDepth = BitSet.of(paramInt);
      return localLookahead;
    }
    Lookahead localLookahead = FOLLOW(paramInt, paramRuleEndElement);
    return localLookahead;
  }

  public Lookahead look(int paramInt, RuleRefElement paramRuleRefElement)
  {
    int[] arrayOfInt;
    int i;
    if (this.DEBUG_ANALYZER)
      System.out.println("lookRuleRef(" + paramInt + "," + paramRuleRefElement + ")");
    RuleSymbol localRuleSymbol = (RuleSymbol)this.grammar.getSymbol(paramRuleRefElement.targetRule);
    if ((localRuleSymbol == null) || (!(localRuleSymbol.defined)))
    {
      this.tool.error("no definition of rule " + paramRuleRefElement.targetRule, this.grammar.getFilename(), paramRuleRefElement.getLine(), paramRuleRefElement.getColumn());
      return new Lookahead();
    }
    RuleBlock localRuleBlock = localRuleSymbol.getBlock();
    RuleEndElement localRuleEndElement = localRuleBlock.endNode;
    boolean bool = localRuleEndElement.noFOLLOW;
    localRuleEndElement.noFOLLOW = true;
    Lookahead localLookahead1 = look(paramInt, paramRuleRefElement.targetRule);
    if (this.DEBUG_ANALYZER)
      System.out.println("back from rule ref to " + paramRuleRefElement.targetRule);
    localRuleEndElement.noFOLLOW = bool;
    if (localLookahead1.cycle != null)
      this.tool.error("infinite recursion to rule " + localLookahead1.cycle + " from rule " + paramRuleRefElement.enclosingRuleName, this.grammar.getFilename(), paramRuleRefElement.getLine(), paramRuleRefElement.getColumn());
    if (localLookahead1.containsEpsilon())
    {
      if (this.DEBUG_ANALYZER)
        System.out.println("rule ref to " + paramRuleRefElement.targetRule + " has eps, depth: " + localLookahead1.epsilonDepth);
      localLookahead1.resetEpsilon();
      arrayOfInt = localLookahead1.epsilonDepth.toArray();
      localLookahead1.epsilonDepth = null;
      for (i = 0; i < arrayOfInt.length; ++i)
      {
        int j = paramInt - paramInt - arrayOfInt[i];
        Lookahead localLookahead2 = paramRuleRefElement.next.look(j);
        localLookahead1.combineWith(localLookahead2);
      }
    }
    return localLookahead1;
  }

  public Lookahead look(int paramInt, StringLiteralElement paramStringLiteralElement)
  {
    if (this.DEBUG_ANALYZER)
      System.out.println("lookStringLiteral(" + paramInt + "," + paramStringLiteralElement + ")");
    if (this.lexicalAnalysis)
    {
      if (paramInt > paramStringLiteralElement.processedAtomText.length())
        return paramStringLiteralElement.next.look(paramInt - paramStringLiteralElement.processedAtomText.length());
      return Lookahead.of(paramStringLiteralElement.processedAtomText.charAt(paramInt - 1));
    }
    if (paramInt > 1)
      return paramStringLiteralElement.next.look(paramInt - 1);
    Lookahead localLookahead = Lookahead.of(paramStringLiteralElement.getType());
    if (paramStringLiteralElement.not)
    {
      int i = this.grammar.tokenManager.maxTokenType();
      localLookahead.fset.notInPlace(4, i);
    }
    return localLookahead;
  }

  public Lookahead look(int paramInt, SynPredBlock paramSynPredBlock)
  {
    if (this.DEBUG_ANALYZER)
      System.out.println("look=>(" + paramInt + "," + paramSynPredBlock + ")");
    return paramSynPredBlock.next.look(paramInt);
  }

  public Lookahead look(int paramInt, TokenRangeElement paramTokenRangeElement)
  {
    if (this.DEBUG_ANALYZER)
      System.out.println("lookTokenRange(" + paramInt + "," + paramTokenRangeElement + ")");
    if (paramInt > 1)
      return paramTokenRangeElement.next.look(paramInt - 1);
    BitSet localBitSet = BitSet.of(paramTokenRangeElement.begin);
    for (int i = paramTokenRangeElement.begin + 1; i <= paramTokenRangeElement.end; ++i)
      localBitSet.add(i);
    return new Lookahead(localBitSet);
  }

  public Lookahead look(int paramInt, TreeElement paramTreeElement)
  {
    if (this.DEBUG_ANALYZER)
      System.out.println("look(" + paramInt + "," + paramTreeElement.root + "[" + paramTreeElement.root.getType() + "])");
    if (paramInt > 1)
      return paramTreeElement.next.look(paramInt - 1);
    Lookahead localLookahead = null;
    if (paramTreeElement.root instanceof WildcardElement)
    {
      localLookahead = paramTreeElement.root.look(1);
    }
    else
    {
      localLookahead = Lookahead.of(paramTreeElement.root.getType());
      if (paramTreeElement.root.not)
      {
        int i = this.grammar.tokenManager.maxTokenType();
        localLookahead.fset.notInPlace(4, i);
      }
    }
    return localLookahead;
  }

  public Lookahead look(int paramInt, WildcardElement paramWildcardElement)
  {
    BitSet localBitSet;
    if (this.DEBUG_ANALYZER)
      System.out.println("look(" + paramInt + "," + paramWildcardElement + ")");
    if (paramInt > 1)
      return paramWildcardElement.next.look(paramInt - 1);
    if (this.lexicalAnalysis)
    {
      localBitSet = (BitSet)((LexerGrammar)this.grammar).charVocabulary.clone();
    }
    else
    {
      localBitSet = new BitSet(1);
      int i = this.grammar.tokenManager.maxTokenType();
      localBitSet.notInPlace(4, i);
      if (this.DEBUG_ANALYZER)
        System.out.println("look(" + paramInt + "," + paramWildcardElement + ") after not: " + localBitSet);
    }
    return new Lookahead(localBitSet);
  }

  public Lookahead look(int paramInt, ZeroOrMoreBlock paramZeroOrMoreBlock)
  {
    if (this.DEBUG_ANALYZER)
      System.out.println("look*(" + paramInt + "," + paramZeroOrMoreBlock + ")");
    Lookahead localLookahead1 = look(paramInt, paramZeroOrMoreBlock);
    Lookahead localLookahead2 = paramZeroOrMoreBlock.next.look(paramInt);
    localLookahead1.combineWith(localLookahead2);
    return localLookahead1;
  }

  public Lookahead look(int paramInt, String paramString)
  {
    if (this.DEBUG_ANALYZER)
      System.out.println("lookRuleName(" + paramInt + "," + paramString + ")");
    RuleSymbol localRuleSymbol = (RuleSymbol)this.grammar.getSymbol(paramString);
    RuleBlock localRuleBlock = localRuleSymbol.getBlock();
    if (localRuleBlock.lock[paramInt] != 0)
    {
      if (this.DEBUG_ANALYZER)
        System.out.println("infinite recursion to rule " + localRuleBlock.getRuleName());
      return new Lookahead(paramString);
    }
    if (localRuleBlock.cache[paramInt] != null)
    {
      if (this.DEBUG_ANALYZER)
        System.out.println("found depth " + paramInt + " result in FIRST " + paramString + " cache: " + localRuleBlock.cache[paramInt].toString(",", this.charFormatter, this.grammar));
      return ((Lookahead)localRuleBlock.cache[paramInt].clone());
    }
    localRuleBlock.lock[paramInt] = true;
    Lookahead localLookahead = look(paramInt, localRuleBlock);
    localRuleBlock.lock[paramInt] = false;
    localRuleBlock.cache[paramInt] = ((Lookahead)localLookahead.clone());
    if (this.DEBUG_ANALYZER)
      System.out.println("saving depth " + paramInt + " result in FIRST " + paramString + " cache: " + localRuleBlock.cache[paramInt].toString(",", this.charFormatter, this.grammar));
    return localLookahead;
  }

  public static boolean lookaheadEquivForApproxAndFullAnalysis(Lookahead[] paramArrayOfLookahead, int paramInt)
  {
    for (int i = 1; i <= paramInt - 1; ++i)
    {
      BitSet localBitSet = paramArrayOfLookahead[i].fset;
      if (localBitSet.degree() > 1)
        return false;
    }
    return true;
  }

  private void removeCompetingPredictionSets(BitSet paramBitSet, AlternativeElement paramAlternativeElement)
  {
    AlternativeElement localAlternativeElement1 = this.currentBlock.getAlternativeAt(this.currentBlock.analysisAlt).head;
    if (localAlternativeElement1 instanceof TreeElement)
    {
      if (((TreeElement)localAlternativeElement1).root == paramAlternativeElement)
        break label43;
      return;
    }
    if (paramAlternativeElement != localAlternativeElement1)
      return;
    for (int i = 0; i < this.currentBlock.analysisAlt; ++i)
    {
      label43: AlternativeElement localAlternativeElement2 = this.currentBlock.getAlternativeAt(i).head;
      paramBitSet.subtractInPlace(localAlternativeElement2.look(1).fset);
    }
  }

  private void removeCompetingPredictionSetsFromWildcard(Lookahead[] paramArrayOfLookahead, AlternativeElement paramAlternativeElement, int paramInt)
  {
    for (int i = 1; i <= paramInt; ++i)
      for (int j = 0; j < this.currentBlock.analysisAlt; ++j)
      {
        AlternativeElement localAlternativeElement = this.currentBlock.getAlternativeAt(j).head;
        paramArrayOfLookahead[i].fset.subtractInPlace(localAlternativeElement.look(i).fset);
      }
  }

  private void reset()
  {
    this.grammar = null;
    this.DEBUG_ANALYZER = false;
    this.currentBlock = null;
    this.lexicalAnalysis = false;
  }

  public void setGrammar(Grammar paramGrammar)
  {
    if (this.grammar != null)
      reset();
    this.grammar = paramGrammar;
    this.lexicalAnalysis = this.grammar instanceof LexerGrammar;
    this.DEBUG_ANALYZER = this.grammar.analyzerDebug;
  }

  public boolean subruleCanBeInverted(AlternativeBlock paramAlternativeBlock, boolean paramBoolean)
  {
    if ((paramAlternativeBlock instanceof ZeroOrMoreBlock) || (paramAlternativeBlock instanceof OneOrMoreBlock) || (paramAlternativeBlock instanceof SynPredBlock))
      return false;
    if (paramAlternativeBlock.alternatives.size() == 0)
      return false;
    for (int i = 0; i < paramAlternativeBlock.alternatives.size(); ++i)
    {
      Alternative localAlternative = paramAlternativeBlock.getAlternativeAt(i);
      if ((localAlternative.synPred != null) || (localAlternative.semPred != null) || (localAlternative.exceptionSpec != null))
        return false;
      AlternativeElement localAlternativeElement = localAlternative.head;
      if (((!(localAlternativeElement instanceof CharLiteralElement)) && (!(localAlternativeElement instanceof TokenRefElement)) && (!(localAlternativeElement instanceof CharRangeElement)) && (!(localAlternativeElement instanceof TokenRangeElement)) && (((!(localAlternativeElement instanceof StringLiteralElement)) || (paramBoolean)))) || (!(localAlternativeElement.next instanceof BlockEndElement)) || (localAlternativeElement.getAutoGenType() != 1))
        return false;
    }
    return true;
  }
}